package org.ascollada.core
{
	import flash.errors.IllegalOperationError;
	
	import org.ascollada.core.ns.collada;
	
	/**
	 * @author Tim Knip
	 */ 
	public class DaeSampler extends DaeElement
	{
		use namespace collada;
		
		public var channel :DaeChannel;
		public var input :Array;
		public var output :Array;
		
		/**
		 * 
		 */ 
		public function get endTime():Number
		{
			if(!input || !input.length)
				return NaN;	
			return input[input.length-1];
		}
		
		/**
		 * 
		 */ 
		public function get startTime():Number
		{
			if(!input || !input.length)
				return NaN;	
			return input[0];
		}
		
		/**
		 * 
		 */ 
		public function DaeSampler(document:DaeDocument, element:XML=null)
		{
			super(document, element);
		}
		
		/**
		 * 
		 */ 
		public function outputToMatrix(transform:DaeTransform):void
		{	
			if(!channel || !output || !output.length) return;
			
			var member :String = channel.targetMember;
			var x :Number, y :Number, z :Number, rad :Number;
			var i :int;
			
			switch(transform.type)
			{
				case "rotate":
					if(member == "ANGLE" && transform.data.length == 4)
					{
						x = transform.data[0];
						y = transform.data[1];
						z = transform.data[2];
						for(i = 0; i < output.length; i++)
						{
							rad = output[i] * (Math.PI/180);
							
							output[i] = buildRotation(x, y, z, rad);
						}
					}
					break;
				case "scale":
					if(transform.data.length == 3)
					{ 
						x = transform.data[0];
						y = transform.data[1];
						z = transform.data[2];
						for(i = 0; i < output.length; i++)
						{
							switch(member)
							{
								case "X":
									output[i] = buildScale(output[i], y, z);
									break;
								case "Y":
									output[i] = buildScale(x, output[i], z);
									break;
								case "Z":
									output[i] = buildScale(x, y, output[i]);
									break;
								default:
									break;
							}
						}
					}
					break;
				case "translate":
					if(transform.data.length == 3)
					{ 
						x = transform.data[0];
						y = transform.data[1];
						z = transform.data[2];
						for(i = 0; i < output.length; i++)
						{
							switch(member)
							{
								case "X":
									output[i] = buildTranslation(output[i], y, z);
									break;
								case "Y":
									output[i] = buildTranslation(x, output[i], z);
									break;
								case "Z":
									output[i] = buildTranslation(x, y, output[i]);
									break;
								default:
									break;
							}
						}
					}
					break;
				case "matrix":
				default:
					if(output[0].length != 16) throw new IllegalOperationError("damn!");
					break;
			}
		}
		
		/**
		 * @inheritDoc
		 */ 
		public override function read(element:XML):void
		{
			super.read(element);
			
			var daeInput :DaeInput;
			var el :XML;
			var list :XMLList = element.input;
			var source :DaeSource;
			var i :int;
			
			for each(el in list)
			{
				daeInput = new DaeInput(this.document, el);	
				
				source = this.document.sources[ daeInput.source ];
				if(!source)
				{
					throw new IllegalOperationError("Could not find source data!");
				}
				
				switch(daeInput.semantic)
				{
					case "INPUT":
						this.input = source.data;
						break;
					case "OUTPUT":
						this.output = source.data;
						break;
					default:
						break;
				}
			}
		}
		
		private function buildRotation(x:Number, y:Number, z:Number, rad:Number):Array
		{
			var m :Array = new Array(16);
			
			var nCos:Number	= Math.cos( rad );
			var nSin:Number	= Math.sin( rad );
			var scos:Number	= 1 - nCos;
	
			var sxy	:Number = x * y * scos;
			var syz	:Number = y * z * scos;
			var sxz	:Number = x * z * scos;
			var sz	:Number = nSin * z;
			var sy	:Number = nSin * y;
			var sx	:Number = nSin * x;
	
			m[0] =  nCos + x * x * scos;
			m[1] = -sz   + sxy;
			m[2] =  sy   + sxz;
			m[3] = 0;
			
			m[4] =  sz   + sxy;
			m[5] =  nCos + y * y * scos;
			m[6] = -sx   + syz;
			m[7] = 0;
			
			m[8] = -sy   + sxz;
			m[9] =  sx   + syz;
			m[10] =  nCos + z * z * scos;
			m[11] = 0;
			
			m[12] = 0;
			m[13] = 0;
			m[14] = 0;
			m[15] = 1;
			
			return m;
		}
		
		private function buildScale(x:Number, y:Number, z:Number):Array
		{
			var m :Array = [
				x, 0, 0, 0,
				0, y, 0, 0,
				0, 0, z, 0,
				0, 0, 0, 1
			];
			return m;
		}
		
		private function buildTranslation(x:Number, y:Number, z:Number):Array
		{
			var m :Array = [
				1, 0, 0, x,
				0, 1, 0, y,
				0, 0, 1, z,
				0, 0, 0, 1
			];
			return m;
		}
	}
}